#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <unistd.h>
#include <pthread.h>

using namespace std;

int tickets = 1000; // 加锁保证共享资源的安全
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//全局的锁或者静态的锁可以使用宏进行初始化，可以不销毁

//细节：
//1：在不同的线程访问同一个临界资源的时候，都必须使用同一把锁。
//2：锁也是一份公共资源，那么我们如何保证这个临界资源的安全呢？，答：加锁和解锁的操作都是原子性的，不会并发的加锁和解锁
//3：每个线程在加锁的时候，虽然我们可以在任意的地方进行加锁，但是一般不会那么做，以为加锁的本质就是让不同的线程串行的访问临界区，所以我们加锁的粒度一定
     //要尽可能的细，这样才能在保证程序并发执行的同时，效率的损耗更小。
//4：临界区可以是一行代码或者一份代码区间。那么在某个线程执行临界区的代码的时候，是否可以被切换呢？答：可以的，因为不同的线程共用的是同一把锁
//当我们持有锁的线程被挂起的时候，其他线程就得不到锁，从而就无法进入临界区。

class Data
{
public:
    Data(string name, pthread_mutex_t* pmutex)
        :_name(name)
        ,_pmutex(pmutex)
    {}

    string _name;
    pthread_mutex_t* _pmutex;
};

void *threadRoutine(void *args)
{
    Data* td = static_cast<Data*>(args);

    while(true)
    {
        pthread_mutex_lock(td->_pmutex); // 所有线程都要遵守这个规则
        if(tickets > 0) // tickets == 1; a, b, c,d
        {
            //a,b,c,d
            usleep(1000); // 模拟抢票花费的时间  单位微秒
            cout << td->_name << " get a ticket: " << tickets-- << endl;
            pthread_mutex_unlock(td->_pmutex);//解锁
        }
        else
        {
            pthread_mutex_unlock(td->_pmutex);//解锁
            break;
        }
        //充当抢完一张票，后续动作
        //usleep(1000); 
    }

    return nullptr;
}

int main()
{
    pthread_mutex_t mutex;//局部的锁就必须使用pthread_mutex_init函数进行初始化，在不使用时进行销毁
    pthread_mutex_init(&mutex, nullptr);//锁初始化

    pthread_t t[4];
    int n = sizeof(t)/sizeof(t[0]);
    for(int i = 0; i < n; i++)
    {
        char name[64];
        snprintf(name, 64, "thread-%d", i+1);
        Data* td = new Data(name, &mutex);
        pthread_create(t+i, nullptr, threadRoutine, td);
    }

    for(int i = 0; i < n; i++)
    {
        pthread_join(t[i], nullptr);
    }

    pthread_mutex_destroy(&mutex);
    return 0;
}









// // __thread int g_val = 100;

// int g_val = 100;

// std::string hexAddr(pthread_t tid)
// {
//     g_val++;
//     char buffer[64];
//     snprintf(buffer, sizeof(buffer), "0x%x", tid);

//     return buffer;
// }

// void *threadRoutine(void* args)
// {
//     // static int a = 10;
//     string name = static_cast<const char*>(args);
//     int cnt = 5;
//     while(cnt)
//     {
//         // cout << name << " : " << cnt-- << " : " << hexAddr(pthread_self()) << " &cnt: " << &cnt << endl;
//         cout << name << " g_val: " << g_val++ << ", &g_val: " << &g_val << endl;
//         sleep(1);
//     }
//     return nullptr;
// }

// int main()
// {
//     pthread_t t1, t2, t3;
//     pthread_create(&t1, nullptr, threadRoutine, (void*)"thread 1"); // 线程被创建的时候，谁先执行不确定！
//     pthread_create(&t2, nullptr, threadRoutine, (void*)"thread 2"); // 线程被创建的时候，谁先执行不确定！
//     pthread_create(&t3, nullptr, threadRoutine, (void*)"thread 3"); // 线程被创建的时候，谁先执行不确定!

//     pthread_join(t1, nullptr);
//     pthread_join(t2, nullptr);
//     pthread_join(t3, nullptr);

//     // pthread_detach(tid);

//     // while(true)
//     // {
//     //     cout << " main thread:  " << hexAddr(pthread_self()) << " new thread id: " << hexAddr(tid) << endl;
//     //     sleep(1);
//     // }

//     // if( 0 != n )
//     // {
//     //     std::cerr << "error: " << n << " : " <<  strerror(n) << std::endl;
//     // }

//     // sleep(10);
//     return 0;
// }


// void run1()
// {
//     while(true)
//     {
//         cout << "thread 1" << endl;
//         sleep(1);
//     }
// }
// void run2()
// {
//     while(true)
//     {
//         cout << "thread 2" << endl;
//         sleep(1);
//     }
// }
// void run3()
// {
//     while(true)
//     {
//         cout << "thread 3" << endl;
//         sleep(1);
//     }
// }


// int main()
// {
//     thread th1(run1);
//     thread th2(run2);
//     thread th3(run3);

//     th1.join();
//     th2.join();
//     th3.join();

//     return 0;
// }